import { ResultEnum } from "@/enums/httpEnum";
import { MessageType } from "@/enums/messageEnum";
import { saveAs } from "file-saver";
import { ElMessageBox, ElNotification } from "element-plus";
import { dayjs } from "element-plus";
import i18n from "@/languages/index";
import { GlobalStore } from "@/stores";
const { t } = i18n.global;
/**
 * @description 获取localStorage
 * @param {String} key Storage名称
 * @return string
 */
export function localGet(key: string) {
	const value = window.localStorage.getItem(key);
	try {
		return JSON.parse(window.localStorage.getItem(key) as string);
	} catch (error) {
		return value;
	}
}

/**
 * @description 存储localStorage
 * @param {String} key Storage名称
 * @param {Any} value Storage值
 * @return void
 */
export function localSet(key: string, value: any) {
	window.localStorage.setItem(key, JSON.stringify(value));
}

/**
 * @description 清除localStorage
 * @param {String} key Storage名称
 * @return void
 */
export function localRemove(key: string) {
	window.localStorage.removeItem(key);
}

/**
 * @description 清除所有localStorage
 * @return void
 */
export function localClear() {
	window.localStorage.clear();
}

export function randomVal(min: number, max: number, size: number) {
	let result = [];
	size = size || 1;
	max = max || 100;
	for (let i = 0; i < size; i++) {
		result.push(Math.floor(Math.random() * (max - min + 1) + min));
	}
	return result;
}

/**
 * @description 判断数据类型
 * @param {Any} val 需要判断类型的数据
 * @return string
 */
export function isType(val: any) {
	if (val === null) return "null";
	if (typeof val !== "object") return typeof val;
	else return Object.prototype.toString.call(val).slice(8, -1).toLocaleLowerCase();
}

/**
 * @description 生成唯一 uuid
 * @return string
 */
export function generateUUID() {
	if (typeof crypto === "object") {
		if (typeof crypto.randomUUID === "function") {
			return crypto.randomUUID();
		}
		if (typeof crypto.getRandomValues === "function" && typeof Uint8Array === "function") {
			const callback = (c: any) => {
				const num = Number(c);
				return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString(16);
			};
			return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, callback);
		}
	}
	let timestamp = new Date().getTime();
	let performanceNow = (typeof performance !== "undefined" && performance.now && performance.now() * 1000) || 0;
	return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
		let random = Math.random() * 16;
		if (timestamp > 0) {
			random = (timestamp + random) % 16 | 0;
			timestamp = Math.floor(timestamp / 16);
		} else {
			random = (performanceNow + random) % 16 | 0;
			performanceNow = Math.floor(performanceNow / 16);
		}
		return (c === "x" ? random : (random & 0x3) | 0x8).toString(16);
	});
}
export const generateSn = function () {
	return generateId(16);
};
export const generateId = function (len: number) {
	let res = "";
	// var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
	let possible = "0123456789";
	let numPossible = possible.length;
	for (let i = 0; i < len; i++) {
		res += possible.charAt((Math.random() * numPossible) | 0);
	}
	return res;
};

/**
 * 判断两个对象是否相同
 * @param a 要比较的对象一
 * @param b 要比较的对象二
 * @returns 相同返回 true，反之则反
 */
export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]: any }) {
	if (!a || !b) return false;
	let aProps = Object.getOwnPropertyNames(a);
	let bProps = Object.getOwnPropertyNames(b);
	if (aProps.length != bProps.length) return false;
	for (let i = 0; i < aProps.length; i++) {
		let propName = aProps[i];
		let propA = a[propName];
		let propB = b[propName];
		if (!b.hasOwnProperty(propName)) return false;
		if (propA instanceof Object) {
			if (!isObjectValueEqual(propA, propB)) return false;
		} else if (propA !== propB) {
			return false;
		}
	}
	return true;
}

/**
 * @description 生成随机数
 * @param {Number} min 最小值
 * @param {Number} max 最大值
 * @return number
 */
export function randomNum(min: number, max: number): number {
	let num = Math.floor(Math.random() * (min - max) + max);
	return num;
}

/**
 * @description 获取当前时间对应的提示语
 * @return string
 */
export function getTimeState() {
	// 获取当前时间
	let timeNow = new Date();
	// 获取当前小时
	let hours = timeNow.getHours();
	// 判断当前时间段
	if (hours >= 6 && hours <= 10) return `早上好`;
	if (hours >= 10 && hours <= 14) return `中午好`;
	if (hours >= 14 && hours <= 18) return `下午好`;
	if (hours >= 18 && hours <= 24) return `晚上好`;
	if (hours >= 0 && hours <= 6) return `凌晨好`;
}

/**
 * @description 获取浏览器默认语言
 * @return string
 */
export function getBrowserLang() {
	// let browserLang = navigator.language ? navigator.language : navigator.browserLanguage;
	// let defaultBrowserLang = "";
	// if (browserLang.toLowerCase() === "cn" || browserLang.toLowerCase() === "zh" || browserLang.toLowerCase() === "zh-cn") {
	// 	defaultBrowserLang = "zh";
	// } else {
	// 	defaultBrowserLang = "en";
	// }
	// return defaultBrowserLang;
	return GlobalStore().language;
}

/**
 * @description 扁平化数组对象(主要用来处理路由菜单)
 * @param {Array} menuList 所有菜单列表
 * @return array
 */
export function getFlatArr(menuList: Menu.MenuOptions[]) {
	let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList));
	return newMenuList.reduce((pre: Menu.MenuOptions[], current: Menu.MenuOptions) => {
		let flatArr = [...pre, current];
		if (current.children) flatArr = [...flatArr, ...getFlatArr(current.children)];
		return flatArr;
	}, []);
}

/**
 * @description 处理 prop 为多级嵌套的情况(列如: prop:user.name)
 * @param {Object} row 当前行数据
 * @param {String} prop 当前 prop
 * @return any
 * */
export function handleRowAccordingToProp(row: { [key: string]: any }, prop: string) {
	if (!prop.includes(".")) return row[prop] ?? "--";
	prop.split(".").forEach(item => (row = row[item] ?? "--"));
	return row;
}

/**
 * @description 处理 prop，当 prop 为多级嵌套时 ==> 返回最后一级 prop
 * @param {String} prop 当前 prop
 * @return string
 * */
export function handleProp(prop?: string): string {
	if (!prop) {
		return "";
	}
	const propArr = prop.split(".");
	if (propArr.length == 1) return prop;
	return propArr[propArr.length - 1];
}

/**
 * @description 根据枚举列表查询当需要的数据（如果指定了 label 和 value 的 key值，会自动识别格式化）
 * @param {String} callValue 当前单元格值
 * @param {Array} enumData 字典列表
 * @param {Array} fieldNames 指定 label && value 的 key 值
 * @param {String} type 过滤类型（目前只有 tag）
 * @return string
 * */
export function filterEnum(
	callValue: any,
	enumData: any[] | undefined,
	fieldNames?: { label: string; value: string },
	type?: string
): string {
	const value = fieldNames?.value ?? "value";
	const label = fieldNames?.label ?? "label";
	let filterData: { [key: string]: any } = {};
	if (Array.isArray(enumData)) filterData = enumData.find((item: any) => item[value] === callValue);
	if (type == "tag") return filterData?.tagType ? filterData.tagType : "";
	return filterData ? filterData[label] : "--";
}

interface Confirm {
	title?: string;
	content?: string;
	ok?: string;
	cancel?: string;
	hideCancel?: boolean;
}
export function confirm(
	param: Confirm = {
		title: "操作确认",
		content: "确定提交当前数据记录？",
		ok: "确定",
		cancel: "取消",
		hideCancel: false
	}
) {
	return new Promise(resolve => {
		ElMessageBox.confirm(param.content, param.title, {
			confirmButtonText: param.ok,
			cancelButtonText: param.cancel,
			type: "warning",
			draggable: true
		})
			.then(() => {
				resolve(true);
			})
			.catch(() => {
				resolve(false);
			});
	});
}
export function showMsg(msg: string | undefined, type?: boolean | MessageType) {
	let msgType = type == true || type == null ? MessageType.success : type == false ? MessageType.error : type;
	ElNotification({
		title: t("common.showmsg.title"),
		message: msg,
		dangerouslyUseHTMLString: true,
		type: msgType as MessageType
	});
}

/**
 * 使用操作模块错误信息
 * @param code
 * @param prefixMsg
 * @returns
 */
export function showTips(code: number, prefixMsg: string | undefined, errMsg?: string) {
	let message;
	if (code != ResultEnum.SUCCESS && errMsg) {
		message = errMsg;
	} else {
		message = (prefixMsg || "操作") + (code == ResultEnum.SUCCESS ? t("common.showtips.success") : t("common.showtips.fail"));
	}
	showMsg(message, code == ResultEnum.SUCCESS ? MessageType.success : MessageType.error);
	return code == ResultEnum.SUCCESS;
}
/**
 * Jsonpath特殊符号处理
 * @param value
 * @param character
 * @returns
 */
export function assJsonpathData(value: string, character: string = "$") {
	return character == "$" ? `$.${value}` : `$..${value}`;
}

/**
 * 深度拷贝方法，JSON.parse(JSON.stringify) 进阶版
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source: any) {
	if (!source && typeof source !== "object") {
		throw new Error("error arguments, deepClone");
	}
	const targetObj = source.constructor === Array ? ([] as any) : {};
	Object.keys(source).forEach(keys => {
		if (source[keys] && typeof source[keys] === "object") {
			targetObj[keys] = deepClone(source[keys]);
		} else {
			targetObj[keys] = source[keys];
		}
	});
	return targetObj;
}

// 获取地址栏参数
export function GetQueryString(href?: string) {
	const params = {} as any;
	href = href || window.location.href;
	if (href.indexOf("=") > 1) {
		const paramArray = href.split("?")[1].split("&");
		if (paramArray.length > 0) {
			paramArray.forEach(function (currentValue) {
				params[currentValue.split("=")[0]] = currentValue.split("=")[1];
			});
		}
	}
	return params;
}

/**
 * 将树结构转化为list
 * @param {*} list
 * @param {*} pid
 * @returns
 */
export function treeDataToList(list: any, pid = 0) {
	const arr = [] as any;
	list.forEach((item: any) => {
		const info = deepClone(item);
		delete info.children;
		info.pid = pid;
		arr.push(info);
		if (item.children && item.children.length) {
			const list = treeDataToList(item.children, item.id);
			arr.push(...list);
		}
	});
	return arr;
}
/**
 * 过滤集合重复数据
 * @param arr
 * @returns
 */
export function unique(arr: Array<any>) {
	return arr.filter(function (item, index, arr) {
		//当前元素，在原始数组中的第一个索引==当前索引值，否则返回当前元素
		return arr.indexOf(item, 0) === index;
	});
}
/**
 * 复制内容到剪切板
 * @param text
 */
export function copyToClipboard(text: any) {
	const dummy = document.createElement("textarea");
	document.body.appendChild(dummy);
	dummy.value = text;
	dummy.select();
	document.execCommand("copy");
	document.body.removeChild(dummy);
}

interface ht {
	text: string; // 搜索内容
	dom: any; // 搜索节点内容
	index: number; // 当前索引 开始为0
}
/**
 *
 * @param obj 参数对象
 */
export function htmlFilter(obj: ht) {
	// index = 0;
	// console.log(obj.index);
	// eslint-disable-next-line prefer-const
	// document.querySelector 这里获取标签需要自己换一下
	let main = obj.dom || document.querySelector("body");
	let innerHTML = main.innerHTML;
	// 如果要兼容IE就使用下面的正则 （谷歌 IE 都可以使用）
	//innerHTML = innerHTML.replace(new RegExp('<[^>]+>', 'g'), function(str) {
	//return str.replace(new RegExp('(<\/?em.*?>)|(<\/?strong.*?>)', 'g'), '')
	//})
	//------ 这行代码不兼容IE
	const emReg1 = new RegExp('<em style="background-color: yellow">', "g");
	innerHTML = innerHTML.replace(emReg1, "");
	const emReg2 = new RegExp("</em>", "g");
	innerHTML = innerHTML.replace(emReg2, "");
	const emReg3 = new RegExp('<strong style="background-color: #ff9632">', "g");
	innerHTML = innerHTML.replace(emReg3, "");
	const emReg4 = new RegExp("</strong>", "g");
	innerHTML = innerHTML.replace(emReg4, "");
	// ------
	main.innerHTML = innerHTML;
	// 设置本次搜索背景色
	if (obj.text !== "" && obj.text !== " ") {
		const reg = new RegExp(obj.text, "g");
		const searchText = obj.text;
		const mainInnerHTML = innerHTML.replace(new RegExp("(?=>).+?(?=<)", "g"), function (str: string) {
			const reg1 = new RegExp("(?=>).+", "g");
			return str.replace(new RegExp("(>).+", "g"), function (str2: string) {
				return str2.replace(reg1, function (str1: string) {
					return str1.replace(reg, '<em style="background-color: yellow">' + searchText + "</em>");
				});
			});
		});
		main.innerHTML = mainInnerHTML;
	}
	const num = document.getElementsByTagName("em").length;
	if (num !== 0) {
		document.getElementsByTagName("em")[obj.index].innerHTML =
			'<strong style="background-color: #5E7CE0;">' + obj.text + "</strong>";
		if (obj.index == 0) {
			// 滚动到第一个关键字位置
			document.getElementsByTagName("em")[obj.index].scrollIntoView({
				block: "start",
				behavior: "smooth"
			});
		} else {
			document.getElementsByTagName("em")[obj.index].scrollIntoView();
		}
	}
	if (obj.index >= num - 1) {
		obj.index = 0;
	} else {
		obj.index++;
	}
}
// scrollTop animation
export const scrollTop = (el: HTMLElement | any, from: number = 0, to: number, duration: number = 500, endCallback: Function) => {
	if (!window.requestAnimationFrame) {
		window.requestAnimationFrame =
			(window as any).webkitRequestAnimationFrame ||
			(window as any).mozRequestAnimationFrame ||
			(window as any).msRequestAnimationFrame ||
			function (callback) {
				return window.setTimeout(callback, 1000 / 60);
			};
	}
	const difference = Math.abs(from - to);
	const step = Math.ceil((difference / duration) * 50);

	const scroll = (start: number, end: number, step: number) => {
		if (start === end) {
			endCallback && endCallback();
			return;
		}

		let d = start + step > end ? end : start + step;
		if (start > end) {
			d = start - step < end ? end : start - step;
		}

		if (el === window) {
			window.scrollTo(d, d);
		} else {
			el.scrollTop = d;
		}
		window.requestAnimationFrame(() => scroll(d, end, step));
	};
	scroll(from, to, step);
};
/**
 * 时间范围补全
 * @param startTime
 * @param endTime
 * @param dateType
 * @returns {Array}
 */
export function timeRangeFull(startTime: string, endTime: string, dateType: "hour" | "day" | "month" | "year") {
	let timeMap = [];
	let fmt = "YYYY-MM-DD HH";
	switch (dateType) {
		case "hour":
			fmt = "YYYY-MM-DD HH";
			break;
		case "day":
			fmt = "YYYY-MM-DD";
			break;
		case "month":
			fmt = "YYYY-MM-01";
			break;
		case "year":
			fmt = "YYYY-MM";
			break;
	}
	//时间格式转换
	let startTimeDts = dayjs(dayjs(startTime).format(fmt), fmt);
	let endTimeDts = dayjs(dayjs(endTime).format(fmt), fmt);

	//补全
	while (startTimeDts.valueOf() < endTimeDts.valueOf()) {
		timeMap.push(startTimeDts.format("YYYY-MM-DD HH:mm:ss"));
		startTimeDts.add(1, dateType);
	}

	//补全最后1个
	timeMap.push(startTimeDts.format("YYYY-MM-DD HH:mm:ss"));
	return timeMap;
}
//文件导出
export function exportExcel(data: any, filename: string) {
	// const url = URL.createObjectURL(res.data);
	// const link = document.createElement("a");
	// document.body.appendChild(link);
	// link.download = decodeURI(res.headers["file-name"]);
	// link.href = url;
	// link.click();
	// document.body.removeChild(link);
	// URL.revokeObjectURL(url);

	const blob = new Blob([data]);
	saveAs(blob, decodeURIComponent(filename));
}
//文件导出
export function exportFile(res: any) {
	const url = URL.createObjectURL(res.data);
	const link = document.createElement("a");
	document.body.appendChild(link);
	link.download = decodeURI(res.filename);
	link.href = url;
	link.click();
	document.body.removeChild(link);
	URL.revokeObjectURL(url);
}
//是否是三三应用
export function isSystem(res: any) {
	if (res.startsWith("http")) {
		return res.includes(window.location.hostname);
	} else {
		return true;
	}
}
